home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacWorld 1999 February
/
Macworld (1999-02).dmg
/
Cinema 4D GO demo
/
Gumption Plug-ins
/
Plug-ins
/
Freeware
/
ShrinkWrap
/
ShrinkWrap.cof
Wrap
Text File
|
1998-05-03
|
6KB
|
254 lines
/*
The Shrinkwrap plugin wraps a closed polygon mesh, more or less like a rubber sheet,
around a group of perfect spheres (sorry, spheres only).
Send comments, praise, money :-) etc. to:
Jim Hasselbrook
hassel@bellatlantic.net
This software is provided free, AS IS. Feel free to modify it for any non-commercial purposes.
*/
copy(doc, obj, newname)
{
var i;
var pcount = obj->GetPointCount();
var ecount = obj->GetEdgeCount();
var tcount = obj->GetTriangleCount();
var qcount = obj->GetQuadrangleCount();
var newobj = doc->NewPolygonObject(newname, NULL, NULL, pcount, ecount, tcount, qcount);
var t = new(Triangle);
var q = new(Quadrangle);
var e = new(Edge);
var mat = new(Matrix);
obj->GetMg(mat); // obj to world coords
for (i=0; i<pcount; i++) {
//StatusSetBar(i*100.0/pcount, TRUE);
newobj->SetPoint(i, mat->MulP(obj->GetPoint(i)));
}
for (i=0; i<ecount; i++) {
//StatusSetBar(i*100.0/ecount, TRUE);
obj->GetEdge(i, e);
newobj->SetEdge(i, e);
}
for (i=0; i<tcount; i++) {
//StatusSetBar(i*100.0/tcount, TRUE);
obj->GetTriangle(i, t);
newobj->SetTriangle(i, t);
}
for (i=0; i<qcount; i++) {
//StatusSetBar(i*100.0/qcount, TRUE);
obj->GetQuadrangle(i, q);
newobj->SetQuadrangle(i, q);
}
if (GetC4DVersion() >= 5003)
{
newobj->Optimize(TRUE,TRUE,TRUE,TRUE);
}
newobj->UpdateObject();
return newobj;
}
isOutsideBoundary(p, bound)
{
var obj;
var origin, bbox;
for (obj = bound->GetDown(); obj != NULL; obj = obj->GetNext())
{
origin = obj->GetPosition();
bbox = obj->GetBox2();
if (vlen(p-origin) <= bbox.x) return obj;
}
return NULL;
}
doShrink(doc, newobj, boundgrp, iter, vacuum)
{
var i, j;
var pcount = newobj->GetPointCount();
var tcount = newobj->GetTriangleCount();
var grad = new(array, pcount);
var norms = new(array, pcount);
var edges = new(array, pcount);
var ta = new(array, tcount);
var tb = new(array, tcount);
var tc = new(array, tcount);
var p = new(array, pcount);
var t = new(Triangle);
var new_point;
var vzero = vector(0.0, 0.0, 0.0);
/* copying the data into arrays seems faster
* than calling the accessors over and over
*/
for (i=0; i<pcount; i++)
{
p[i] = newobj->GetPoint(i);
grad[i] = vzero;
norms[i] = vzero;
edges[i] = 0;
}
for (i=0; i<tcount; i++)
{
newobj->GetTriangle(i, t);
ta[i] = t->a;
tb[i] = t->b;
tc[i] = t->c;
}
var a_i, b_i, c_i;
var ab, bc, ca, norm;
var ab_squared, bc_squared, ca_squared;
for (j=0; j<iter; j++)
{
StatusSetBar(j*100.0/iter, TRUE);
//StatusSetText("Calculating gradients", TRUE);
for (i=0; i<tcount; i++)
{
a_i = ta[i]; b_i = tb[i]; c_i = tc[i];
ab = p[a_i] - p[b_i];
bc = p[b_i] - p[c_i];
ca = p[c_i] - p[a_i];
ab_squared = vnorm(ab) * vlen(ab) * vlen(ab);
bc_squared = vnorm(bc) * vlen(bc) * vlen(bc);
ca_squared = vnorm(ca) * vlen(ca) * vlen(ca);
grad[a_i] += ca_squared - ab_squared; edges[a_i] += 2;
grad[b_i] += ab_squared - bc_squared; edges[b_i] += 2;
grad[c_i] += bc_squared - ca_squared; edges[c_i] += 2;
norm = vcross(ca, ab);
norms[a_i] += norm;
norms[b_i] += norm;
norms[c_i] += norm;
}
//StatusSetText("Moving points", TRUE);
for (i=0; i<pcount; i++)
{
//StatusSetBar(i*100.0/pcount, TRUE);
new_point = p[i] + vnorm(grad[i]) * sqrt(vlen(grad[i])) / edges[i]
- (vnorm(norms[i]) * sqrt(vlen(norms[i])) / edges[i]) * vacuum / 2.0;
var boundobj = isOutsideBoundary(new_point, boundgrp);
if (boundobj == NULL)
{
p[i] = new_point;
}
else // place along surface
{
var origin = boundobj->GetPosition();
var bbox = boundobj->GetBox2();
p[i] = origin + vnorm(new_point - origin) * bbox.x;
}
newobj->SetPoint(i, p[i]);
grad[i] = vzero;
norms[i] = vzero;
edges[i] = 0;
}
doc->RedrawAll(FALSE, FALSE, FALSE);
}
newobj->UpdateObject();
return newobj;
}
/*
* Create a flattened list of boundary objects,
* translated to world coordinates
*/
copyBounds(doc, boundgrp, boundtemp, last)
{
var obj, newobj;
var mg = new(Matrix);
for (obj = boundgrp->GetDown(); obj != NULL; obj = obj->GetNext())
{
newobj = doc->CopyObject(obj, boundtemp, last, COPY_NO_HIERARCHY);
obj->GetMg(mg);
newobj->SetMg(mg);
last = copyBounds(doc, obj, boundtemp, newobj);
}
return last;
}
shrink(doc)
{
var obj, newobj;
var mg = new(Matrix);
obj = doc->FindFirstActiveObject();
if(!obj || !instanceof(obj,PolygonObject))
{
TextDialog("Must select a polygon object!", DLG_OK);
return;
}
var d = new (SimpleDialog);
d->SetData(0,"Boundary Group",FIELD_STRING,0.0,0.0,"Object group");
d->SetData(1,"Iterations",FIELD_INTEGER,1,100,1);
d->SetData(2,"Vacuum (-1.0 to 2.0)",FIELD_FLOAT,-1.0,2.0,0.0);
d->SetTitle("Shrink Wrap");
if (!d->DoDialog()) return FALSE;
var boundgrp = doc->FindObject(d->GetData(0));
var iter = d->GetData(1);
var vacuum = d->GetData(2);
if(!boundgrp || !boundgrp->GetDown())
{
TextDialog("Must select a boundary group!", DLG_OK);
return;
}
if(obj->GetQuadrangleCount() > 0)
{
TextDialog("Please triangulate first!", DLG_OK);
return;
}
newobj = copy(doc, obj, obj->GetName());
doc->KillObject(obj);
doc->ActivateObject(newobj);
var boundtemp = doc->NewPolygonObject("temp bound group", NULL, NULL, 0, 0, 0, 0);
copyBounds(doc, boundgrp, boundtemp, NULL);
doShrink(doc, newobj, boundtemp, iter, vacuum);
doc->KillObject(boundtemp);
doc->SendMessage(DOCUMENT_CHANGED);
StatusClear();
}
main()
{
RegisterMenuHook("Shrinkwrap","shrink");
}